package com.duojuhe.security.shiro.filter;

import com.duojuhe.security.shiro.StatelessAuthenticationToken;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.utils.jsonutils.JsonUtils;
import com.duojuhe.common.utils.token.TokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 公共接口拦截
 */
@Slf4j
public class ShiroCommonControlFilter extends AccessControlFilter {
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest req, ServletResponse resp) throws Exception {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        try {
            // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
           if (RequestMethod.OPTIONS.name().equals(request.getMethod().toUpperCase())) {
                response.setStatus(HttpStatus.OK.value());
                return false;
            }
            String reqUrl = request.getRequestURI();
            //token值
            String token = TokenUtils.getTokenByRequest(request);
            if (StringUtils.isBlank(token)) {
                JsonUtils.write(response, ServiceResult.fail(ErrorCodes.TOKEN_IS_NULL_ERROR));
                log.error("token参数为空，参数：reqUrl: {}",reqUrl);
                return false;
            }
            // 委托给Realm进行验证
            getSubject(request, response).login(new StatelessAuthenticationToken(token, null));
            return true;
        }catch (CredentialsException | LockedAccountException e) {
            if (e instanceof CredentialsException) {
                JsonUtils.write(response, ServiceResult.fail(ErrorCodes.KICK_OUT_ERROR));
            } else {
                JsonUtils.write(response, ServiceResult.fail(ErrorCodes.LOCK_SCREEN_ERROR));
            }
            return false;
        }catch (AuthenticationException e) {
            JsonUtils.write(response, ServiceResult.fail(ErrorCodes.TOKEN_ERROR));
            return false;
        }
    }
}
